home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
nn.zip
/
PACK_NAM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-31
|
10KB
|
497 lines
/*
* pack_name(packed, name, length)
* pack sender's name into something sensible, return in packed
*
*/
#include "config.h"
#define SEP_DOT 0 /* . */
#define SEP_PERCENT 1 /* % */
#define SEP_SCORE 2 /* _ */
#define SEP_AMPERSAND 3 /* @ */
#define SEP_BANG 4 /* ! */
#define SEP_MAXIMUM 5
#define CL_OK 0x0100 /* letter or digit */
#define CL_SPACE 0x0200 /* cvt to space */
#define CL_IGNORE 0x0400 /* ignore */
#define CL_RANGE(c) 0x0800+c /* space range, end with c */
#define CL_HYPHEN 0x1000 /* convert to - */
#define CL_STOP 0x2000 /* discard rest of name */
#define CL_SEP | 0x4000 + /* address separator */
#define IS_OK(c) (Class[c] & CL_OK)
#define IS_SPACE(c) (Class[c] & CL_SPACE)
#define IGNORE(c) (c & 0x80 || Class[c] & CL_IGNORE)
#define BEGIN_RANGE(c) (Class[c] & CL_RANGE(0))
#define END_RANGE(c) (Class[c] & 0xff)
#define IS_HYPHEN(c) (Class[c] & CL_HYPHEN)
#define IS_STOP(c) (Class[c] & CL_STOP)
#define IS_SEPARATOR(c) (Class[c] & (0 CL_SEP 0))
static short Class[128] = {
/* NUL */ CL_STOP ,
/* SOH */ CL_IGNORE ,
/* STX */ CL_IGNORE ,
/* ETX */ CL_IGNORE ,
/* EOT */ CL_IGNORE ,
/* ENQ */ CL_IGNORE ,
/* ACK */ CL_IGNORE ,
/* BEL */ CL_IGNORE ,
/* BS */ CL_IGNORE ,
/* TAB */ CL_SPACE ,
/* NL */ CL_IGNORE ,
/* VT */ CL_IGNORE ,
/* FF */ CL_IGNORE ,
/* CR */ CL_IGNORE ,
/* SO */ CL_IGNORE ,
/* SI */ CL_IGNORE ,
/* DLE */ CL_IGNORE ,
/* DC1 */ CL_IGNORE ,
/* DC2 */ CL_IGNORE ,
/* DC3 */ CL_IGNORE ,
/* DC4 */ CL_IGNORE ,
/* NAK */ CL_IGNORE ,
/* SYN */ CL_IGNORE ,
/* ETB */ CL_IGNORE ,
/* CAN */ CL_IGNORE ,
/* EM */ CL_IGNORE ,
/* SUB */ CL_IGNORE ,
/* ESC */ CL_IGNORE ,
/* FS */ CL_IGNORE ,
/* GS */ CL_IGNORE ,
/* RS */ CL_IGNORE ,
/* US */ CL_IGNORE ,
/* space */ CL_SPACE ,
/* ! */ CL_SPACE CL_SEP SEP_BANG,
/* " */ CL_RANGE( '"' ) ,
/* # */ CL_OK ,
/* $ */ CL_OK ,
/* % */ CL_OK CL_SEP SEP_PERCENT,
/* & */ CL_OK ,
/* ' */ CL_OK ,
/* ( */ CL_RANGE( ')' ) ,
/* ) */ CL_IGNORE ,
/* * */ CL_HYPHEN ,
/* + */ CL_HYPHEN ,
/* , */ CL_STOP ,
/* - */ CL_HYPHEN ,
/* . */ CL_SPACE CL_SEP SEP_DOT,
/* / */ CL_OK ,
/* 0 */ CL_OK ,
/* 1 */ CL_OK ,
/* 2 */ CL_OK ,
/* 3 */ CL_OK ,
/* 4 */ CL_OK ,
/* 5 */ CL_OK ,
/* 6 */ CL_OK ,
/* 7 */ CL_OK ,
/* 8 */ CL_OK ,
/* 9 */ CL_OK ,
/* : */ CL_IGNORE ,
/* ; */ CL_STOP ,
/* < */ CL_IGNORE ,
/* = */ CL_HYPHEN ,
/* > */ CL_IGNORE ,
/* ? */ CL_IGNORE ,
/* @ */ CL_OK CL_SEP SEP_AMPERSAND,
/* A */ CL_OK ,
/* B */ CL_OK ,
/* C */ CL_OK ,
/* D */ CL_OK ,
/* E */ CL_OK ,
/* F */ CL_OK ,
/* G */ CL_OK ,
/* H */ CL_OK ,
/* I */ CL_OK ,
/* J */ CL_OK ,
/* K */ CL_OK ,
/* L */ CL_OK ,
/* M */ CL_OK ,
/* N */ CL_OK ,
/* O */ CL_OK ,
/* P */ CL_OK ,
/* Q */ CL_OK ,
/* R */ CL_OK ,
/* S */ CL_OK ,
/* T */ CL_OK ,
/* U */ CL_OK ,
/* V */ CL_OK ,
/* W */ CL_OK ,
/* X */ CL_OK ,
/* Y */ CL_OK ,
/* Z */ CL_OK ,
/* [ */ CL_OK ,
/* \ */ CL_OK ,
/* ] */ CL_OK ,
/* ^ */ CL_IGNORE ,
/* _ */ CL_SPACE CL_SEP SEP_SCORE,
/* ` */ CL_IGNORE ,
/* a */ CL_OK ,
/* b */ CL_OK ,
/* c */ CL_OK ,
/* d */ CL_OK ,
/* e */ CL_OK ,
/* f */ CL_OK ,
/* g */ CL_OK ,
/* h */ CL_OK ,
/* i */ CL_OK ,
/* j */ CL_OK ,
/* k */ CL_OK ,
/* l */ CL_OK ,
/* m */ CL_OK ,
/* n */ CL_OK ,
/* o */ CL_OK ,
/* p */ CL_OK ,
/* q */ CL_OK ,
/* r */ CL_OK ,
/* s */ CL_OK ,
/* t */ CL_OK ,
/* u */ CL_OK ,
/* v */ CL_OK ,
/* w */ CL_OK ,
/* x */ CL_OK ,
/* y */ CL_OK ,
/* z */ CL_OK ,
/* { */ CL_OK ,
/* | */ CL_OK ,
/* } */ CL_OK ,
/* ~ */ CL_HYPHEN ,
/* DEL */ CL_IGNORE
} ;
pack_name(dest, source, length)
char *dest, *source;
int length;
{
register char *p, *q, *r, c;
register int n;
char namebuf[129], *name;
char *maxq;
int lname, lfirst, lmiddle, llast, sep, i;
int drop_space, prev_space;
char *separator[SEP_MAXIMUM];
dest[0] = NUL;
if (source == NULL || source[0] == NUL)
return 0;
p = source, q = namebuf, n = 0;
maxq = namebuf + sizeof namebuf - 1;
new_partition:
for (i = SEP_MAXIMUM; --i >= 0; separator[i] = NULL);
while ( c = *p++ ) {
if (c == '<') {
while (q > namebuf && q[-1] == SP) q--;
if (q == namebuf) continue;
break;
}
if (IGNORE(c)) continue;
if (q == namebuf && IS_SPACE(c)) continue;
if (c == '(') {
if (*p == ')') {
p++;
continue;
}
if (n++ == 0) {
q = namebuf;
goto new_partition;
}
continue;
}
if (c == ')') {
if (--n == 0) break;
continue;
}
if (n > 1) continue;
if (q >= maxq) break;
*q++ = c;
if (IS_SEPARATOR(c)) {
switch (sep = (Class[c] & 0xff)) {
case SEP_DOT:
if (separator[SEP_AMPERSAND] && q - namebuf <= length)
break;
continue;
case SEP_BANG:
if (separator[SEP_AMPERSAND]) continue;
break;
default:
if (separator[sep]) continue;
break;
}
separator[sep] = q - 1;
}
}
*q = NUL;
if (namebuf[0] == NUL) return 0;
name = namebuf;
if (name[0] == '"') {
name++;
if (q[-1] == '"') *--q = NUL;
}
if (q - name <= length) goto name_ok;
/* sorry for the many goto's -- the 3B2 C compiler does not */
/* make correct code for complicated logical expressions!! */
/* not even without -O */
/* We must pack the name to make it fit */
/* Name_of_person%... -> Name_of_person */
if (r = separator[SEP_PERCENT]) {
if (!(q = separator[SEP_SCORE]) || q > r )
goto no_percent;
if ((q = separator[SEP_AMPERSAND]) && q < r)
goto no_percent;
if ((q = separator[SEP_BANG]) && q < r)
goto no_percent;
*r = NUL;
goto parse_name;
}
no_percent:
/* name@site.domain -> name@site */
if (r = separator[SEP_AMPERSAND]) {
if ((q = separator[SEP_PERCENT]) && q < r) {
*r = NUL;
if (r - name <= length) goto name_ok;
*q = NUL;
if (((p = separator[SEP_BANG]) && p < q)
|| ((p = strrchr(name, '!')) && p < q)) {
name = p + 1;
}
if (strchr(name, '.'))
goto parse_name;
goto name_ok;
}
if (q = separator[SEP_DOT]) {
*q = NUL;
goto name_ok;
}
*r = NUL;
if (r - name <= length) goto name_ok;
if ((q = separator[SEP_BANG]) && q < r) {
name = q + 1;
goto name_ok;
}
#ifdef NOTDEF
if (strchr(name, '!') == NULL)
goto parse_name; /* take the chance ... */
#endif
goto name_ok; /* can't do it any better */
}
/* Phase 1: Normalization (remove superfluous characters) */
parse_name:
for (p = name, lname = 0, prev_space = 0; c = *p; p++) {
/*
if (IGNORE(c)) {
*p = TAB;
if (p == name) name++;
continue;
}
*/
if (IS_OK(c)) {
lname++;
prev_space = 0;
continue;
}
if (IS_HYPHEN(c)) {
if (p == name) {
name++;
continue;
}
if (prev_space)
*p = TAB;
else {
*p = '-';
lname++;
}
continue;
}
if (BEGIN_RANGE(c)) {
if (p == name) {
name++;
continue;
}
c = END_RANGE(c);
for (q = p+1; *q && *q != c; q++);
if (*q) {
if (p[-1] != ' ') lname++;
while (p <= q) *p++ = ' ';
p--;
prev_space++;
continue;
}
c = ' ';
}
if (IS_SPACE(c)) {
*p = ' ';
if (p == name)
name++;
else
if (!prev_space) {
lname++;
prev_space++;
}
continue;
}
if (IS_STOP(c)) {
*p = NUL;
break;
}
}
drop_last_name:
while (p > name && (*--p == ' ' || *p == TAB)) *p = NUL;
if (lname < length) goto name_ok;
/* Phase 2: Reduce middle names */
for (r = p, llast = 0; r > name && *r != ' '; r--)
if (*r != TAB) llast++;
/* r points to space before last name */
if (strncmp(r, " Jr", 3) == 0 || strncmp(r, " II", 3) == 0) {
p = r+1;
lname -= llast;
goto drop_last_name;
}
if (r == name) goto phase6; /* only last name */
for (q = name, lfirst = 0; *q && *q != ' '; q++)
if (*q != TAB) lfirst++;
/* q points at space after first name */
for (p = q, lmiddle = 0; p < r; ) {
/* find next middle name */
while (p < r && (*p == ' ' || *p == TAB)) p++;
if (p >= r) break; /* found last name */
p++; /* skip first char of middle name */
for (;*p != ' '; p++) { /* remove rest */
if (*p == TAB) continue;
*p = TAB;
lname--;
}
lmiddle += 2; /* initial + space */
}
if (lname < length) goto name_ok;
/* If removing middle names is not enough, but reducing first name instead is, do it that way */
if (lname - lmiddle >= length && lname - lfirst + 1 < length) goto phase4;
/* Phase 3: Remove middle names */
for (p = q; p < r; p++) {
if (*p == TAB) continue;
if (*p == ' ') continue;
*p = TAB;
lname -= 2;
}
if (lname < length) goto name_ok;
/* Phase 4: Reduce first name */
phase4:
for (p = name+1; p < q; p++) {
if (*p == TAB) continue;
if (*p == ' ') continue;
if (*p == '-' && (p + 1) < q) {
p++;
continue;
}
*p = TAB;
lname--;
}
if (lname < length) goto name_ok;
/* Phase 5: Remove first name */
name = r+1;
lname--;
if (lname < length) goto name_ok;
/* Phase 6: Cut last name */
phase6:
goto name_ok;
name_ok:
q = dest;
maxq = q + length;
drop_space = 1;
for (p = name; *p && q < maxq ; p++) {
if (*p == TAB) continue;
if ( *p == ' ' ) {
if (!drop_space) {
drop_space = 1;
*q++ = ' ';
}
continue;
}
drop_space = 0;
*q++ = *p;
}
*q = NUL;
return strlen(dest);
}